﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CdcSoftware.Pivotal.Applications.Core.Client;
using CdcSoftware.Pivotal.Engine.UI.Forms;
using System.Windows.Forms;
using System.Security.Cryptography;
using CdcSoftware.Pivotal.Engine.Client.Services.Interfaces;
using System.Data;
using CdcSoftware.Pivotal.Engine.Types.Database;
using CdcSoftware.Pivotal.Engine.Types.MailMerges;
using CdcSoftware.Pivotal.Applications.Core.Common;
using CdcSoftware.Pivotal.Engine;
using CdcSoftware.Pivotal.Engine.Types.ServerTasks;

namespace Pcm.Retail.Client.FormTasks
{   
    public partial class RE_Batch : FormClientTask
    {
        /// <summary>
        /// Do not allow the user to add secondary rows if there is noone logged into the store.
        /// </summary>
        /// <param name="sender">The control associated with the event triggered</param>
        /// <param name="args">The argument for the event</param>
        /// <history>
        /// #Revision   Date            Author      Description
        /// 6.0.9.1     2012-01-17      DS          Initial version for Retail.
        /// </history>
        public virtual void OnSecondaryAddClick(PivotalControl sender, EventArgs args)
        {
            try
            {
                System.ComponentModel.CancelEventArgs cancelargs = (System.ComponentModel.CancelEventArgs)args;
                DataTable loggedInStaffs = Globals.GetDataTable("RE_All Active Staff logged in today with Store?", 
                    new object[] { this.PrimaryDataRow["Store_Id"] }, "RE_Staff_Id");
                if (loggedInStaffs == null || loggedInStaffs.Rows.Count == 0)
                {
                    PivotalMessageBox.Show("No Staff found logged in to the Store.", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    cancelargs.Cancel = true;
                    return;
                }
            }
            catch (Exception ex)
            {
                Globals.HandleException(ex, true);
            }
        }

        /// <summary>
        /// Do not allow the user to add secondary rows if there is not cashier logged into the store..
        /// </summary>
        /// <param name="sender">The control associated with the event triggered</param>
        /// <param name="args">The argument for the event</param>
        /// <history>
        /// #Revision   Date            Author      Description
        /// 6.0.9.1     2012-01-17      DS          Initial version for Retail.
        /// </history>
        public virtual void OnSecondaryAddClickCDPO(PivotalControl sender, EventArgs args)
        {
            try
            {
                System.ComponentModel.CancelEventArgs cancelargs = (System.ComponentModel.CancelEventArgs)args;

                DataTable cashierLog = Globals.GetDataTable("RE_All Cashier Logins for Today where EndTime is Null with POS ?",
                    new object[] { this.PrimaryDataRow["RE_POS_Id"] }, "Staff_Id", "Store_Id", "POS_Id", "Batch_Id");

                //One Cashier logged in
                if (cashierLog == null || cashierLog.Rows.Count == 0)
                {
                    PivotalMessageBox.Show("No Cashier found logged in to the POS.", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    cancelargs.Cancel = true;
                    return;
                }
            }
            catch (Exception ex)
            {
                Globals.HandleException(ex, true);
            }
        }

        /// <summary>
        /// Fire the event on change of Status.
        /// </summary>
        /// <param name="sender">The control associated with the event triggered</param>
        /// <param name="args">The argument for the event</param>
        /// <history>
        /// #Revision   Date            Author      Description
        /// 6.0.9.1     2011-09-26      DS          Initial version for Retail.
        /// </history>
        public virtual void OnStatusChange(object sender, EventArgs args)
        {
            try
            {
                if (this.RecordId != null)
                {
                    if ((String.Equals(this.PrimaryDataRow["Batch_Status", DataRowVersion.Original].ToString(), "Closed") &&
                        (String.Equals(this.PrimaryDataRow["Batch_Status"].ToString(), "In Progress") ||
                        String.Equals(this.PrimaryDataRow["Batch_Status"].ToString(), "Open"))) ||
                        (String.Equals(this.PrimaryDataRow["Batch_Status", DataRowVersion.Original].ToString(), "In Progress") &&
                        String.Equals(this.PrimaryDataRow["Batch_Status"].ToString(), "Open")))
                    {
                        PivotalMessageBox.Show("Invalid Status transition.", MessageBoxButtons.OK, MessageBoxIcon.Hand);
                        this.PrimaryDataRow["Batch_Status"] = this.PrimaryDataRow["Batch_Status", DataRowVersion.Original].ToString();
                    }
                }

                //Allow the user to fill the closing amount when the status is Closed.
                if (String.Equals(this.PrimaryDataRow["Batch_Status"].ToString(), "Closed"))
                {
                    Globals.EnableDisableSecondaryFields(true, "RE_Batch_Detail_RE_Batch_Id", new string[] { "Closing_Amount", "Remarks" });
                    //Enable/Disable the Actual Amount for the Batch float type opening/closing.
                    EnableDisableDataGridCell("RE_Batch_Cash_Float_Batch_Id", "Actual_Amount", 0, false);
                    EnableDisableDataGridCell("RE_Batch_Cash_Float_Batch_Id", "Actual_Amount", 1, true);
                    EnableDisableDataGridCell("RE_Batch_Cash_Float_Batch_Id", "Remarks1", 0, false);
                    EnableDisableDataGridCell("RE_Batch_Cash_Float_Batch_Id", "Remarks1", 1, true);
                }
                else
                {
                    Globals.EnableDisableSecondaryFields(false, "RE_Batch_Detail_RE_Batch_Id", new string[] { "Closing_Amount", "Remarks" });
                    //Enable/Disable the Actual Amount for the Batch float type opening/closing.
                    EnableDisableDataGridCell("RE_Batch_Cash_Float_Batch_Id", "Actual_Amount", 0, false);
                    EnableDisableDataGridCell("RE_Batch_Cash_Float_Batch_Id", "Actual_Amount", 1, false);
                    EnableDisableDataGridCell("RE_Batch_Cash_Float_Batch_Id", "Remarks1", 0, false);
                    EnableDisableDataGridCell("RE_Batch_Cash_Float_Batch_Id", "Remarks1", 1, false);
                    if (this.RecordId == null && String.Equals(this.PrimaryDataRow["Batch_Status"].ToString(), "In Progress"))
                    {
                        EnableDisableDataGridCell("RE_Batch_Cash_Float_Batch_Id", "Actual_Amount", 0, true);
                        EnableDisableDataGridCell("RE_Batch_Cash_Float_Batch_Id", "Remarks1", 0, true);
                    }
                }
            }
            catch (Exception ex)
            {
                Globals.HandleException(ex, true);
            }
        }

        /// <summary>
        /// On cell changed of datagrid view cell for Opening Amount.
        /// </summary>
        /// <param name="sender">The control associated with the event triggered</param>
        /// <param name="args">The argument for the event</param>
        /// <history>
        /// #Revision   Date            Author      Description
        /// 6.0.9.1     2011-09-26      DS          Initial version for Retail.
        /// </history>
        /// 
        //public virtual void NegativeCheckOnCellDataSourceUpdated(object sender, EventArgs args)
        //{
        //    try
        //    {
        //        DataGridViewCellEventArgs dgEventArgs = args as DataGridViewCellEventArgs;

        //        if (TypeConvert.ToDouble(this.DataSet.Tables["RE_Batch_Detail_RE_Batch_Id"].Rows[dgEventArgs.RowIndex]["Opening_Amount"]) < 0)
        //        {
        //            PivotalMessageBox.Show("Value cannot be negative.", MessageBoxButtons.OK, MessageBoxIcon.Error);
        //            this.DataSet.Tables["RE_Batch_Detail_RE_Batch_Id"].Rows[dgEventArgs.RowIndex]["Opening_Amount"] = 0;
        //        }
        //    }
        //    catch (Exception ex)
        //    {
        //        Globals.HandleException(ex, true);
        //    }
        //}

        /// <summary>
        /// On cell changed of datagrid view cell for Actual Amount.
        /// </summary>
        /// <param name="sender">The control associated with the event triggered</param>
        /// <param name="args">The argument for the event</param>
        /// <history>
        /// #Revision   Date            Author      Description
        /// 6.0.10.1     2012-06-21      DS          Initial version for Retail.
        /// </history>
        /// 
        public virtual void OnCellDataSourceUpdatedActualAmount(object sender, EventArgs args)
        {
            try
            {
                int rowIndex = ((DataGridViewCellEventArgs)args).RowIndex;
                DataTable cashFloat = this.DataSet.Tables["RE_Batch_Cash_Float_Batch_Id"];

                if (TypeConvert.ToDouble(cashFloat.Rows[rowIndex]["Actual_Amount"]) < 0)
                {
                    PivotalMessageBox.Show("Value can't be negative.", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    cashFloat.Rows[rowIndex]["Actual_Amount"] = DBNull.Value;
                }
                else
                {
                    //Calculate Over/Short Amount.
                    cashFloat.Rows[rowIndex]["Over_Short_Amount"] = TypeConvert.ToDouble(cashFloat.Rows[rowIndex]["Actual_Amount"]) -
                        TypeConvert.ToDouble(this.PrimaryDataRow["Cash_Float"]);
                }
            }
            catch (Exception ex)
            {
                Globals.HandleException(ex, true);
            }
        }

        /// <summary>
        /// Fire the event on click of button Run X.
        /// </summary>
        /// <param name="sender">The control associated with the event triggered</param>
        /// <param name="args">The argument for the event</param>
        /// <history>
        /// #Revision   Date            Author      Description
        /// 6.0.9.1     2011-10-12      DS          Initial version for Retail.
        /// </history>
        public virtual void OnClickRunX(object sender, EventArgs args)
        {
            try
            {
                if (this.FormView.Dirty)
                {
                    PivotalMessageBox.Show("The form data has been modified. Please save the changes before Run X.", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    return;
                }
                else
                    SharedRunXandZ(true, false);
            }
            catch (Exception ex)
            {
                Globals.HandleException(ex, true);
            }
        }

        /// <summary>
        /// Shares the code for Both RunX and RunZ execution.
        /// </summary>
        /// <param name="isRunX">true, if simulating RunX button click, otherwise false.</param>
        /// <param name="fromSaveRecord">true, indicates that the call is from SaveRecord method, false otherwise.</param>
        /// <history>
        /// #Revision   Date            Author      Description
        /// 6.0.9.1     2011-11-11      DS          Initial version for Retail.
        /// </history>
        private bool SharedRunXandZ(bool isRunX, bool fromSaveRecord)
        {
            bool isOverShort = false;
            if (!isRunX)
            {
                this.PrimaryDataRow["Closed_Date"] = DateTime.Now;

                //HD:08/Mar/2012:Issue Fix 31:Start:
                foreach (DataRow dr in this.DataSet.Tables["RE_Batch_Detail_RE_Batch_Id"].Rows)
                {
                    if ((dr["Expected_Amount"]) == DBNull.Value || TypeConvert.ToDouble(dr["Expected_Amount"]) == 0)
                    {
                        if ((dr["Closing_Amount"]) == DBNull.Value)
                            dr["Closing_Amount"] = 0;
                    }
                }
                //HD:08/Mar/2012:Issue Fix 31:End:

                if ((this.DataSet.Tables["RE_Batch_Detail_RE_Batch_Id"].AsEnumerable().Count(a => TypeConvert.ToDouble(a["Expected_Amount"]) > 0) > 0))
                {
                    if (this.DataSet.Tables["RE_Batch_Detail_RE_Batch_Id"].AsEnumerable().Count(a => (a["Closing_Amount"] == DBNull.Value)) > 0)
                    {
                        PivotalMessageBox.Show("Please enter Closing Amount corresponding to the tender type where expected amount is not zero.", 
                            MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return false;
                    }
                }

                if (Convert.IsDBNull(this.DataSet.Tables["RE_Batch_Cash_Float_Batch_Id"].Rows[1]["Actual_Amount"])
                        || (this.DataSet.Tables["RE_Batch_Cash_Float_Batch_Id"].Rows[1]["Actual_Amount"] == null))
                {
                    PivotalMessageBox.Show("Actual amount is mandatory for Cash Float type 'Closing' while closing the Batch.", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return false;
                }

                if (this.DataSet.Tables["RE_Batch_Cash_Float_Batch_Id"].AsEnumerable().Count(a => TypeConvert.ToDouble(a["Over_Short_Amount"]) != 0
                    && String.IsNullOrWhiteSpace(a["Remarks"].ToString())) > 0)
                {
                    PivotalMessageBox.Show("Remarks is mandatory corresponding to the row, where Over/Short Amount is not zero for Cash Float.",
                        MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return false;
                }

                //If sum of Over/Short Amount < 0, do not allow Batch closure.
                if (TypeConvert.ToDouble(this.PrimaryDataRow["Over_Short_Amount@Special"]) < 0)
                {
                    //NN 09 Jul 2012:
                    //Chnaged the message by addeding " or equal to" to the text.
                    PivotalMessageBox.Show("Sum of Over/Short Amount should be greater than or equal to Zero.", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return false;
                }
            }         
            
            //Calculate Batch_Sales.
            //Get all Orders from SFA_Order where RE_Batch_Id = recordId.
            //Get RE_Order_Tender for each Tender_Type with the Order_Ids obtained in the last step.
            DataTable orderTenders = Globals.GetDataTable("RE_All Order Tenders with Order Status as Processed for Batch?", new object[] { this.RecordId }, "Tender_Type_Id",
                "Tendered_Amount");

            if (orderTenders != null && orderTenders.Rows.Count > 0)
            {
                foreach (DataRow dr in this.DataSet.Tables["RE_Batch_Detail_RE_Batch_Id"].Rows)
                {
                    //Each row is for specific Tender_Type. So calculate the tender amount for each Tender_Type and put in the corresponding row in Batch_Sales.
                    //Make sure not to add the amount each time the button is clicked rather replace the new value with the old.

                    dr["Batch_Sales"] = (orderTenders.AsEnumerable().Where(a => Id.Create(a["Tender_Type_Id"]) == 
                        Id.Create(dr["Tender_Type_Id"]))).Sum(a => TypeConvert.ToDouble(a["Tendered_Amount"]));

                    //For Tender_Type Cash, SUM all the amounts in the Cashdrop/Payout secondary and fill the value in Batch Cashdrop/Payout corresponding to the row.
                    //For other tender_types, set it to 0.
                    //And Add the Change amount to Cash row.
                    if (Id.Create(dr["Tender_Type_Id"]) == Id.Create(Globals.ServerSqlFind("RE_Tender_Type", "Tender_Type", "Cash")))
                    {
                        dr["Batch_CD_PO"] = this.DataSet.Tables["RE_CashDrop_Payout_RE_Batch_Id"].AsEnumerable().Sum(a => TypeConvert.ToDouble(a["Amount"]));
                        dr["Batch_Sales"] = TypeConvert.ToDouble(dr["Batch_Sales"]) + (orderTenders.AsEnumerable().Where(a => Id.Create(a["Tender_Type_Id"]) ==
                        Id.Create(Globals.ServerSqlFind("RE_Tender_Type", "Tender_Type", "Change")))).Sum(a => TypeConvert.ToDouble(a["Tendered_Amount"]));
                    }
                    else
                        dr["Batch_CD_PO"] = 0;

                    //Batch Amount = Batch Sales - Batch CashDrop/Payout
                    dr["Batch_Amount"] = TypeConvert.ToDouble(dr["Batch_Sales"]) - TypeConvert.ToDouble(dr["Batch_CD_PO"]);

                    //HD:08/Mar/2012:Issue Fix 28:Start:
                    //The expected amount should be calculated :[Opening Amount + Batch Sales - Batch CashDrop/Payout] for each Tender Type.
                    dr["Expected_Amount"] = TypeConvert.ToDouble(dr["Opening_Amount"]) + TypeConvert.ToDouble(dr["Batch_Amount"]);

                    //The following calculation happens only when the Run X button is pressed with the Batch Status as "Closed" or Run Z is clicked.
                    if (!isRunX)
                    {
                        //Calculate Over_Short Amount.
                        dr["Over_Short_Amount"] = TypeConvert.ToDouble(dr["Closing_Amount"]) - TypeConvert.ToDouble(dr["Expected_Amount"]);

                        //DS: "Over_Short_Amount@Special" is used in stead of "Over_Short_Amount" as this value is rounded to two decimal and displayed here. 
                        //But the real value is not exactly upto two places. So it was never allowing the save to happen.
                        if (TypeConvert.ToDouble(dr["Over_Short_Amount@Special"]) != 0 && String.Equals(dr["Remarks"].ToString(), String.Empty))
                            isOverShort = true;

                        //DS: Calculate the Total Payment Received.
                        dr["Payment_Received"] = TypeConvert.ToDouble(dr["Closing_Amount"]) + TypeConvert.ToDouble(dr["Batch_CD_PO"]);
                    }
                }
            }
            else
            {
                if (!isRunX && PivotalMessageBox.Show("No order tenders for this Batch. Still you want to Close the Batch?", MessageBoxButtons.OKCancel, MessageBoxIcon.Question)
                    == DialogResult.Cancel)
                    return false;
            }

            //Calculate the HeadCount
            this.PrimaryDataRow["Store_Head_Count"] = this.DataSet.Tables["RE_Staff_Target_Batch_Id"].Compute("Sum(Head_Count)", string.Empty);

            //Calculate Totals.
            this.PrimaryDataRow["Opening_Amount"] = this.DataSet.Tables["RE_Batch_Detail_RE_Batch_Id"].AsEnumerable().Sum(a => a.Field<double?>("Opening_Amount"));
            this.PrimaryDataRow["Batch_Sales"] = this.DataSet.Tables["RE_Batch_Detail_RE_Batch_Id"].AsEnumerable().Sum(a => a.Field<double?>("Batch_Sales"));
            this.PrimaryDataRow["Batch_Amount"] = this.DataSet.Tables["RE_Batch_Detail_RE_Batch_Id"].AsEnumerable().Sum(a => a.Field<double?>("Batch_Amount"));
            this.PrimaryDataRow["Batch_CD_PO"] = this.DataSet.Tables["RE_Batch_Detail_RE_Batch_Id"].AsEnumerable().Sum(a => a.Field<double?>("Batch_CD_PO"));
            this.PrimaryDataRow["Expected_Amount"] = this.DataSet.Tables["RE_Batch_Detail_RE_Batch_Id"].AsEnumerable().Sum(a => a.Field<double?>("Expected_Amount"));
            this.PrimaryDataRow["Closing_Amount"] = this.DataSet.Tables["RE_Batch_Detail_RE_Batch_Id"].AsEnumerable().Sum(a => a.Field<double?>("Closing_Amount"));
            this.PrimaryDataRow["Over_Short_Amount"] = this.DataSet.Tables["RE_Batch_Detail_RE_Batch_Id"].AsEnumerable().Sum(a => a.Field<double?>("Over_Short_Amount"));

            //Calculate the Batch parameters.
            DataTable orderProducts = Globals.GetDataTable("RE_All Order Products with Order as Processed and Batch?", new object[] { this.RecordId }, "RE_Revenue",
               "RE_Extended_Price", "RE_Unit_Cost_Price", "Quantity");
            DataTable orders = Globals.GetDataTable("RE_All Orders with Status as Processed and Batch?", new object[] { this.RecordId }, "RE_Total_Qty",
               "SFA_Order_Id");
            
            this.PrimaryDataRow["Batch_Sales_BT"] = orderProducts.AsEnumerable().Sum(a => a.Field<double?>("RE_Revenue"));
            this.PrimaryDataRow["Batch_Sales_AT"] = orderProducts.AsEnumerable().Sum(a => a.Field<double?>("RE_Extended_Price"));
            this.PrimaryDataRow["Target_Percent_Achieved"] = (TypeConvert.ToDouble(this.PrimaryDataRow["Store_Target"]) != 0D) ? 
                ((TypeConvert.ToDouble(this.PrimaryDataRow["Batch_Sales_BT"]) / TypeConvert.ToDouble(this.PrimaryDataRow["Store_Target"])) * 100) : 0D;
            this.PrimaryDataRow["Batch_Gross_Profit"] = TypeConvert.ToDouble(this.PrimaryDataRow["Batch_Sales_BT"]) - 
                orderProducts.AsEnumerable().Sum(a => a.Field<double?>("RE_Unit_Cost_Price"));
            this.PrimaryDataRow["Gross_Profit_Percentage"] = (TypeConvert.ToDouble(this.PrimaryDataRow["Batch_Gross_Profit"]) != 0) ?
                ((TypeConvert.ToDouble(this.PrimaryDataRow["Batch_Sales_BT"]) / TypeConvert.ToDouble(this.PrimaryDataRow["Batch_Gross_Profit"])) * 100) : 0D;
            double floorArea = TypeConvert.ToDouble(Globals.ServerSqlIndex("RE_Store", "Floor_Area", Id.Create(this.PrimaryDataRow["Store_Id"])));
            this.PrimaryDataRow["Sales_PSF"] = (floorArea != 0) ? TypeConvert.ToDouble(this.PrimaryDataRow["Batch_Sales_BT"]) / floorArea : 0D;
            this.PrimaryDataRow["No_Of_Transactions"] = orders.Rows.Count;
            this.PrimaryDataRow["Quantity_Sold"] = orderProducts.AsEnumerable().Sum(a => a.Field<Int32?>("Quantity"));
            this.PrimaryDataRow["Qty_Per_Receipt"] = (TypeConvert.ToDouble(this.PrimaryDataRow["No_Of_Transactions"]) != 0) ?
                TypeConvert.ToDouble(this.PrimaryDataRow["Quantity_Sold"]) / TypeConvert.ToDouble(this.PrimaryDataRow["No_Of_Transactions"]) : 0D;
            this.PrimaryDataRow["Average_Transaction_Value"] = (TypeConvert.ToDouble(this.PrimaryDataRow["No_Of_Transactions"]) != 0) ?
                TypeConvert.ToDouble(this.PrimaryDataRow["Batch_Sales_AT"]) / TypeConvert.ToDouble(this.PrimaryDataRow["No_Of_Transactions"]) : 0D;
            DataTable contacts = Globals.GetDataTable("RE_All Contacts with Batch?", new object[] { this.RecordId }, "Contact_Id","RE_Gender");
            this.PrimaryDataRow["No_Of_Members"] = (contacts != null) ? contacts.Rows.Count : 0;
            //AS : Added two fields No_Of_Members_Male and No_Of_Members_Female - CR XII
            this.PrimaryDataRow["No_Of_Members_Male"]=(contacts != null) ? contacts.AsEnumerable().Count(a => TypeConvert.ToString(a["RE_Gender"])=="Male") : 0;
            this.PrimaryDataRow["No_Of_Members_Female"] = (contacts != null) ? contacts.AsEnumerable().Count(a => TypeConvert.ToString(a["RE_Gender"]) == "Female") : 0;
            //Calculate and Set the total fees collected
            DataTable orderProductsForFees = Globals.GetDataTable("RE_All Order Products for Fees with Order as Processed and Batch?", new object[] { this.RecordId },
                "RE_Revenue", "RE_Extended_Price");

            if (orderProductsForFees != null && orderProductsForFees.Rows.Count > 0)
            {
                this.PrimaryDataRow["Total_Fees_Collected_BT"] = orderProductsForFees.AsEnumerable().Sum(a => a.Field<double?>("RE_Revenue"));
                this.PrimaryDataRow["Total_Fees_Collected_AT"] = orderProductsForFees.AsEnumerable().Sum(a => a.Field<double?>("RE_Extended_Price"));
            }

            //DS:24102012 - Calculate and Set the total Miscalleneous Income collected
            DataTable orderProductsForMiscIncome = Globals.GetDataTable("RE_All Order Products for Misc Income with Order as Processed and Batch?", new object[] { this.RecordId },
                "RE_Revenue", "RE_Extended_Price");

            if (orderProductsForMiscIncome != null && orderProductsForMiscIncome.Rows.Count > 0)
            {
                this.PrimaryDataRow["Total_Miscellaneous_Income_BT"] = orderProductsForMiscIncome.AsEnumerable().Sum(a => a.Field<double?>("RE_Revenue"));
                this.PrimaryDataRow["Total_Miscellaneous_Income_AT"] = orderProductsForMiscIncome.AsEnumerable().Sum(a => a.Field<double?>("RE_Extended_Price"));
            }

            //AS : 20-2-2013 - Calculate the Vouchers Sold/Redeemed while doing a Run X or Run Z.
            //DS: 28052013 - Modified both the queries.
            DataTable orderProductsForVouchersSold = Globals.GetDataTable("RE_All Order Products with Order as Processed and productItemGroup? and Batch?",
                new object[] { this.RecordId }, new string[] { "Quantity" });
            if (orderProductsForVouchersSold != null && orderProductsForVouchersSold.Rows.Count > 0)
                this.PrimaryDataRow["Vouchers_Sold"] = orderProductsForVouchersSold.AsEnumerable().Sum(a => a.Field<Int32?>("Quantity"));
            else
                this.PrimaryDataRow["Vouchers_Sold"] = 0;

            DataTable orderTendersForVouchersReedemed = Globals.GetDataTable("RE_All Order Tenders with Order Status as Processed for Batch and TenderType as Voucher?",
                new object[] {this.RecordId }, new string[] { });
            if (orderTendersForVouchersReedemed != null && orderTendersForVouchersReedemed.Rows.Count > 0)
                this.PrimaryDataRow["Vouchers_Redeemed"] = orderTendersForVouchersReedemed.Rows.Count;
            else
                this.PrimaryDataRow["Vouchers_Redeemed"] = 0;
            //AS :End

            if (isOverShort)
            {
                //Make the remarks mandatory for the tender type.
                PivotalMessageBox.Show("Remarks is mandatory corresponding to the row, where Over/Short Amount is not zero.", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }

            if (!isRunX)
            {
                //DS:02112012 - If older batch is closed, then do not force logout the cashier and staffs.
                if (TypeConvert.ToDateTime(this.PrimaryDataRow["Open_Date"]).Date == DateTime.Today.Date)
                {
                    //Logout the staffs and cashiers forcibly if any open login exists.
                    PivotalMessageBox.Show("All Staffs and Cashiers clocked into this store, will be forcibly clocked out.", MessageBoxButtons.OK, MessageBoxIcon.Information);

                    //Clock out all the staffs and cashiers clocked in. For all the POS the cashiers were logged-in, nullify teh values for In_Charge_Id and Cashier_Id.
                    this.SystemClient.ExecuteServerTask("RE_Store", "ForceClockOutOnBatchClosure", new Type[] { typeof(object) }, new object[] { this.PrimaryDataRow["Store_Id"] });

                    //Set the bottom status strip text.
                    Globals.SetCashierStatusStrip(Globals.StatusStripPane.EnvironmentPane);
                }
                //Shiv -  calculate Bank in amount
                //DS: Bank-In Amount is removed as per the CR-V discussion.
                //Id TenderTypeId = Globals.ServerSqlFind("RE_Tender_Type", "Tender_Type", "Cash");
                //this.PrimaryDataRow["Bank_In_Amount"] = (this.DataSet.Tables["RE_Batch_Detail_RE_Batch_Id"].AsEnumerable().Where(a => Id.Create(a["Tender_Type_Id"]) ==
                //        TenderTypeId)).Sum(a => TypeConvert.ToDouble(a["Closing_Amount"])) - TypeConvert.ToDouble(this.PrimaryDataRow["Cash_Float"]);
            }
            //DS: Bank-In Amount is removed as per the CR-V discussion.
            //else
            //{
            //    //Shiv -  calculate Bank in amount - when Run X is run and status is in progress
            //    Id TenderTypeId = Globals.ServerSqlFind("RE_Tender_Type", "Tender_Type", "Cash");
            //    this.PrimaryDataRow["Bank_In_Amount"] = (this.DataSet.Tables["RE_Batch_Detail_RE_Batch_Id"].AsEnumerable().Where(a => Id.Create(a["Tender_Type_Id"]) ==
            //            TenderTypeId)).Sum(a => TypeConvert.ToDouble(a["Expected_Amount"])) - TypeConvert.ToDouble(this.PrimaryDataRow["Cash_Float"]);
            //}

            if (base.SaveRecord())
            {
                if (!fromSaveRecord)
                {
                    //NN 05 July 2012:
                    //Added LoadRecord call for Page refresh error.
                    this.LoadRecord();
                    OnFormReloaded();
                }
                return true;
            }
            else
                PivotalMessageBox.Show("Something went wrong. Please try again.", MessageBoxButtons.OK, MessageBoxIcon.Error);

            return false;
        }

        /// <summary>
        /// Fire the event on click of button Run Z.
        /// </summary>
        /// <param name="sender">The control associated with the event triggered</param>
        /// <param name="args">The argument for the event</param>
        /// <history>
        /// #Revision   Date            Author      Description
        /// 6.0.9.1     2011-10-12      DS          Initial version for Retail.
        /// </history>
        public virtual void OnClickRunZ(object sender, EventArgs args)
        {
            try
            {
                if (SystemClient.SystemInformation.IsMobile)
                    PivotalMessageBox.Show("Batch can only be closed in online mode.", MessageBoxButtons.OK, MessageBoxIcon.Information);
                else if (VerifyCashierLogin())
                {
                    if (String.Equals(this.PrimaryDataRow["Batch_Status"].ToString(), "Closed"))
                        SharedRunXandZ(false, false);
                    else if (PivotalMessageBox.Show("Batch status will be set to Closed and no more transactions will be possible. Do you want to proceed?",
                        MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.OK)
                    {
                        //Set the Status of the Batch to Closed and set the Closed Date.
                        this.PrimaryDataRow["Batch_Status"] = "Closed";
                        SharedRunXandZ(false, false);
                    }
                }
            }
            catch (Exception ex)
            {
                Globals.HandleException(ex, true);
            }
        }

        /// <summary>
        /// Fire the event on click of button Run Report.
        /// </summary>
        /// <param name="sender">The control associated with the event triggered</param>
        /// <param name="args">The argument for the event</param>
        /// <history>
        /// #Revision   Date            Author      Description
        /// 6.0.9.1     2011-11-11      DS          Initial version for Retail.
        /// </history>
        public virtual void OnClickRunReport(object sender, EventArgs args)
        {
            try
            {
                if (String.Equals(this.PrimaryDataRow["Batch_Status"].ToString(), "In Progress"))
                {
                    Globals.ShowReport("RE_X Report", RecordFilter.IndividualRecord, this.RecordId, null, Destination.window, ActionTargetWindow.Modal);
                }
                else if (String.Equals(this.PrimaryDataRow["Batch_Status"].ToString(), "Closed"))
                {
                    Globals.ShowReport("RE_Z Report", RecordFilter.IndividualRecord, this.RecordId, null, Destination.window, ActionTargetWindow.Modal);

                    //DS: z_report_run check is not required anymore.
                    //if (!TypeConvert.ToBoolean(this.PrimaryDataRow["Z_Report_Printed"]))
                    //{
                    //    this.PrimaryDataRow["Z_Report_Printed"] = true;

                    //    base.SaveRecord();
                    //    this.LoadRecord();
                    //    this.OnFormReloaded();
                    //}
                }
            }
            catch (Exception ex)
            {
                Globals.HandleException(ex, true);
            }
        }

        ///// <summary>
        ///// On exit of the field staff code in secondary.
        ///// </summary>
        ///// <param name="sender">The control associated with the event triggered</param>
        ///// <param name="args">The argument for the event</param>
        ///// <history>
        ///// #Revision   Date            Author      Description
        ///// 6.0.9.1     2011-10-18      DS          Initial version for Retail.
        ///// </history>
        //public virtual void OnExitStaffCodeInSecondary(object sender, EventArgs args)
        //{
        //    try
        //    {
        //        DataGridViewCellEventArgs dgEventArgs = args as DataGridViewCellEventArgs;
        //        if (Convert.IsDBNull(this.DataSet.Tables["RE_Staff_Target_Batch_Id"].Rows[dgEventArgs.RowIndex]["Staff_Code"]))
        //        {
        //            this.DataSet.Tables["RE_Staff_Target_Batch_Id"].Rows[dgEventArgs.RowIndex]["Staff_Id"] = DBNull.Value;
        //            return;
        //        }

        //        //"RE_Active Staff with Staff Code?"
        //        DataTable staff = Globals.GetDataTable("RE_Active Staff with Staff Code?", new object[] { this.DataSet.Tables["RE_Staff_Target_Batch_Id"].Rows[dgEventArgs.RowIndex]["Staff_Code"].ToString() },
        //            new string[] { "RE_Staff_Id" });
        //        if (staff != null && staff.Rows.Count > 0)
        //        {
        //            this.DataSet.Tables["RE_Staff_Target_Batch_Id"].Rows[dgEventArgs.RowIndex]["Staff_Id"] = staff.Rows[0]["RE_Staff_Id"];
        //        }
        //        else
        //        {
        //            PivotalMessageBox.Show("No Staff found for the code entered: " + this.DataSet.Tables["RE_Staff_Target_Batch_Id"].Rows[dgEventArgs.RowIndex]["Staff_Code"].ToString() + "\r\nPlease enter a valid code.",
        //                MessageBoxButtons.OK, MessageBoxIcon.Warning);
        //            this.DataSet.Tables["RE_Staff_Target_Batch_Id"].Rows[dgEventArgs.RowIndex]["Staff_Id"] = DBNull.Value;
        //            this.DataSet.Tables["RE_Staff_Target_Batch_Id"].Rows[dgEventArgs.RowIndex]["Staff_Code"] = DBNull.Value;
        //        }
        //    }
        //    catch (Exception ex)
        //    {
        //        Globals.HandleException(ex, true);
        //    }
        //}

        /// <summary>
        /// On Update of Opened By Staff.
        /// </summary>
        /// <param name="sender">The control associated with the event triggered</param>
        /// <param name="args">The argument for the event</param>
        /// <history>
        /// #Revision   Date            Author      Description
        /// 6.0.12.1    15032013        DS          Initial version for Retail.
        /// </history>
        /// 
        public virtual void OnDataSourceUpdatedOpenedByStaff(object sender, EventArgs args)
        {
            try
            {
                passwordValidated = false;
                if (!Convert.IsDBNull(this.PrimaryDataRow["Opened_By_Id"]))
                {
                    if (TypeConvert.ToBoolean(Globals.ServerSqlIndex("RE_Staff", "Prompt_To_Reset", Id.Create(this.PrimaryDataRow["Opened_By_Id"]))))
                        ShowChangePasswordPopup();
                    else
                        ShowAuthorizationPopup();
                    if (!passwordValidated)
                        this.PrimaryDataRow["Opened_By_Id"] = DBNull.Value;
                }
            }
            catch (Exception ex)
            {
                Globals.HandleException(ex, true);
            }
        }

        /// <summary>
        /// On secondary add click, add 5 rows instead of 1.
        /// </summary>
        /// <param name="sender">The control associated with the event triggered</param>
        /// <param name="args">The argument for the event</param>
        /// <history>
        /// #Revision   Date            Author      Description
        /// 6.0.12.1    20052013        DS          Initial version for Retail.
        /// </history>
        /// 
        public virtual void OnSecondaryAddClickSaleSerial(PivotalControl sender, EventArgs args)
        {
            try
            {
                /*System.ComponentModel.CancelEventArgs dataGridViewCellCancelEventArgs = args as System.ComponentModel.CancelEventArgs;
                DataTable saleSerial = this.FormData.DataSet.Tables["RE_Sale_Serial_Number_Batch_Id"];
                int rowToFocus = -1;
                for (int i = 0; i < 5; i++)
                {
                    DataRow saleSerialRow = saleSerial.NewRow();
                    saleSerial.Rows.Add(saleSerialRow);
                    if (rowToFocus == -1)
                        rowToFocus = saleSerial.Rows.Count == 0 ? 0 : saleSerial.Rows.Count - 1;
                }
                SetFocusOnSecondaryCell((DataGridView)(sender.WindowsControl), "Product_Barcode", rowToFocus);
                dataGridViewCellCancelEventArgs.Cancel = true;*/

                // Added by thangnv on 11/11/2013
                Globals.dtSaleSerialNumber = this.FormData.DataSet.Tables["RE_Sale_Serial_Number_Batch_Id"];
                Globals.DataGridView = (object)sender.WindowsControl;
                Globals.Args = (System.ComponentModel.CancelEventArgs)args;
                Globals.mRowIdx = -1;
                Globals.NewModalForm("RE_Sale_Serial_Number_Entry", null);
                System.ComponentModel.CancelEventArgs dataGridViewCellCancelEventArgs = args as System.ComponentModel.CancelEventArgs;
                dataGridViewCellCancelEventArgs.Cancel = true;

                if (this.RecordId != null) // if batch is existed -->Save & Reload.
                {
                    if (this.SaveRecord())
                    {
                        this.LoadRecord();
                        this.FormView.Dirty = false;
                    }
                }
                return;
            }
            catch (Exception ex)
            {
                Globals.HandleException(ex, true);
            }
        }

        public virtual void OnSecondaryEditClick(PivotalControl sender, DataGridViewCellCancelEventArgs e)
        {
            // Added by thangnv on 11/11/2013
            try
            {
                Globals.dtSaleSerialNumber = this.FormData.DataSet.Tables["RE_Sale_Serial_Number_Batch_Id"];
                Globals.DataGridView = (object)sender.WindowsControl;
                Globals.Args = (System.ComponentModel.CancelEventArgs)e;
                Globals.mRowIdx = e.RowIndex;
                Globals.NewModalForm("RE_Sale_Serial_Number_Entry", null);

                if (this.RecordId != null) // if batch is existed -->Save & Reload.
                {
                    if (this.SaveRecord())
                    {
                        this.LoadRecord();
                        this.FormView.Dirty = false;
                    }
                }
                e.Cancel = true;
                return;
            }
            catch (Exception ex)
            {
                Globals.HandleException(ex, true);
            }
        }
 

        /// <summary>
        /// On cell changed of datagrid view cell for Article Number.
        /// </summary>
        /// <param name="sender">The control associated with the event triggered</param>
        /// <param name="args">The argument for the event</param>
        /// <history>
        /// #Revision   Date            Author      Description
        /// 6.0.12.1    20052013      DS          Initial version for Retail.
        /// </history>
        /// 
        public virtual void OnCellDataSourceUpdatedArticleNumber(object sender, EventArgs args)
        {
            try
            {
                int rowIndex = ((DataGridViewCellEventArgs)args).RowIndex;
                DataTable saleSerial = this.FormData.DataSet.Tables["RE_Sale_Serial_Number_Batch_Id"];
                if (!Convert.IsDBNull(saleSerial.Rows[rowIndex]["Product_Barcode"]) && Convert.IsDBNull(saleSerial.Rows[rowIndex]["Product_Id"]))
                {
                    DataTable product = Globals.GetDataTable("RE_Product for Barcode? Alt Code1? Alt Code2? Alt Code3?",
                        new object[] { saleSerial.Rows[rowIndex]["Product_Barcode"], saleSerial.Rows[rowIndex]["Product_Barcode"], saleSerial.Rows[rowIndex]["Product_Barcode"],
                    saleSerial.Rows[rowIndex]["Product_Barcode"]}, "Product_Id");
                    if (product != null && product.Rows.Count > 0)
                    {
                        saleSerial.Rows[rowIndex]["Product_Id"] = product.Rows[0]["Product_Id"];
                        PivotalMessageBox.Show("No product found for Article Number: " + TypeConvert.ToString(saleSerial.Rows[rowIndex]["Product_Barcode"]),
                                MessageBoxButtons.OK, MessageBoxIcon.Warning);
                        //SetFocusOnSecondaryCell(((DataGridViewColumn)sender).DataGridView, "Serial_Number", rowIndex);
                    }
                    else
                    {
                        if (!popUpShown)
                        {
                            popUpShown = true;
                            PivotalMessageBox.Show("No product found for Article Number: " + TypeConvert.ToString(saleSerial.Rows[rowIndex]["Product_Barcode"]),
                                MessageBoxButtons.OK, MessageBoxIcon.Error);
                            popUpShown = false;
                        }
                        saleSerial.Rows[rowIndex]["Product_Barcode"] = DBNull.Value;
                        //SetFocusOnSecondaryCell(((DataGridViewColumn)sender).DataGridView, "Product_Barcode", rowIndex);
                    }
                }
            }
            catch (Exception ex)
            {
                Globals.HandleException(ex, true);
            }
        }
    }
}